package com.cooqe.collection_snmp.snmpfinder;

import com.alibaba.fastjson.JSONObject;
import com.cooqe.collection_snmp.model.SnmpParameter;
import com.cooqe.collection_snmp.utils.SnmpUtil;
import lombok.extern.slf4j.Slf4j;
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 折戟沉沙铁未销
 * @version V1.0
 * @date 2023/11/14-2023
 * @Description: snmp set 方式进行指标值设置
 */
@Component
@Slf4j
@SuppressWarnings("all")
public class SnmpSetHandle {

    /**
     * snmp set 操作，进行oid 值的设置
     * set 进行设置，(1)需要指定要设置的 oid (2)需要指定该oid 要设置的值  (3) 需要设置改oid对应的type类型 OctetString、Integer(32) ...
     *
     * snmp set中不会出现 : 拼接的情况。snmp进行设置的时候，指定准确的 OID , 不需要尽最大的尝试。
     * ----------------------------------------
     * {
     * "method": "set",
     * "oids": "1.2.3.2.6",
     * "values": "1",
     * "types": "OctetString"
     * }
     * ----------------------------------------
     * {
     * "method": "set",
     * "oids": "1.2.3.2.6,1.2.3.2.7",
     * "values": "1,2",
     * "types": "OctetString,OctetString"
     * }
     * ----------------------------------------
     */
    public static Map<String, List<String>> snmpSet(JSONObject collectParamsObj, SnmpParameter snmpParameter, Target target, Snmp snmp) throws Exception {
        //获取参数 oid
        String oids = collectParamsObj.getString(SnmpUtil.OIDS);
        String[] oidArrays = oids.split(SnmpUtil.REGEX_SEGMENT);
        //获取需要设置的 value 值
        String values = collectParamsObj.getString(SnmpUtil.VALUES);
        String[] valueArray = values.split(SnmpUtil.REGEX_SEGMENT);
        //获取需要设置的 type 类型
        String types = collectParamsObj.getString(SnmpUtil.DATATYPES);
        String[] typeArray = types.split(SnmpUtil.REGEX_SEGMENT);

        //定义解析结果
        Map<String, List<String>> resultMap = new HashMap<>();

        //遍历oid，查询对应的指标值
        for (int i = 0; i < oidArrays.length; i++) {
            //定义参数
            String oid = oidArrays[i];
            String val = valueArray[i];
            String type = typeArray[i];
            PDU pdu = (snmpParameter.getVersion() == SnmpConstants.version3) ? (new ScopedPDU()) : (new PDU());
            pdu.setType(PDU.SET);
            pdu.add(new VariableBinding(new OID(oid), getVariable(val, type)));

            //发送请求
            ResponseEvent responseEvent = snmp.send(pdu, target);

            //校验结果
            if (responseEvent == null) {
                throw new RuntimeException("responseEvent is null error");
            }
            if (responseEvent.getError() != null) {
                throw responseEvent.getError();
            }
            if (responseEvent.getResponse().getErrorStatus() != PDU.noError) {
                throw new RuntimeException(responseEvent.getResponse().getErrorStatus() + ":" + responseEvent.getResponse().getErrorStatusText());
            }

            //获取返回结果
            //map结果是 {1.2.3.2.6: : [beijing]}  (beijing是重新设置上的值)
            List<? extends VariableBinding> variableBindings = responseEvent.getResponse().getVariableBindings();
            for (VariableBinding variableBinding : variableBindings) {
                if (!variableBinding.isException()) {
                    String responseOid = variableBinding.getOid().toString();
                    if (resultMap.get(oid) == null) {
                        resultMap.put(oid, new ArrayList<String>());
                    }
                    List<String> result = resultMap.get(oid);
                    result.add(variableBinding.getVariable().toString());
                }
            }
        }
        return resultMap;
    }

    /**
     * 定义设置的值
     *
     * @param variable
     * @param type
     * @return
     */
    private static Variable getVariable(String variable, String type) {
        switch (type) {
            case "OctetString":
                return new OctetString(variable);
            case "Counter32":
                return new Counter32(Long.valueOf(variable));
            case "Counter64":
                return new Counter64(Long.valueOf(variable));
            case "Integer32":
                return new Integer32(Integer.valueOf(variable));
            case "Gauge32":
                return new Gauge32(Long.valueOf(variable));
            default:
                throw new IllegalArgumentException("Invalid type: " + type);
        }
    }
}